use std::io::stdin;
use std::ops::Add;
use rand::Rng;



const RAND_INT_SCOPE: [&str; 10] = ["0", "1","2","3","4","5","6","7","8","9"];
const RAND_CHAR_SCOPE: [&str; 26] = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"
    , "n","o","p","q", "r","s","t","u","v","w","x","y","z"];
const RAND_SPECIAL_SIGN: [&str;23] =["~", "@", "`", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-"
    , "=", "+", ";", ":", "|", "{", "}","?", "[", "]"];

fn main() {

    loop{
        println!("Please entry param: L, M, H: ");
        let mut buffer = String::new();
        let stdin = stdin();
        let _ = stdin.read_line(&mut buffer);
        let mut password="".to_string();
        let pass_gen = PassGen::new();
        //L low; M medium; H higth
        if !buffer.is_empty() {
            let buf = buffer.trim();
            match buf {
                "L" => {
                    password = pass_gen.low_pass_gen();
                    println!("{:?}",password);
                },
                "M" => {
                    password = pass_gen.medium_pass_gen();
                    println!("{:?}",password);
                },
                "H" => {
                    password = pass_gen.high_pass_gen();
                    println!("{:?}",password);
                },
                _ => {
                    eprintln!("You don't put right param, we will generate password by default option.");
                    password = pass_gen.medium_pass_gen();
                    println!("{:?}",password);
                }
            };
        }else {
            password = pass_gen.low_pass_gen();
            println!("{:?}",password);
        }
    }


}


struct PassGen {}

impl PassGen {

    fn new() ->Self {
        PassGen{}
    }
    // gnerate 8~12 lenght password, contains number and a~z.
    fn low_pass_gen(self) -> String {
        let mut rng = rand::thread_rng();
        let pass_length = rng.gen_range(8..=12);
        let  mut order;

        let mut password = String::new();
        loop {
            if password.len()>=pass_length {
                break;
            }
            order = rng.gen_range(0..=1);
            if order == 0{
                let index = rng.gen_range(0..=9);
                password =password.add(RAND_INT_SCOPE[index]);
            }else {
                let index = rng.gen_range(0..=25);
                password =password.add(RAND_CHAR_SCOPE[index]);
            }
        };
        return password;
    }

    // gnerate 13~16 lenght password, contains number and a~z, A~Z.
    fn medium_pass_gen(self) -> String {
        let mut rng = rand::thread_rng();
        let pass_length = rng.gen_range(13..=16);
        let  mut order;

        let mut password = String::new();
        loop {
            if password.len()>=pass_length {
                break;
            }
            order = rng.gen_range(0..=2);
            if order == 0{
                let index = rng.gen_range(0..=9);
                password =password.add(RAND_INT_SCOPE[index]);
            }else if order==1 {
                let index = rng.gen_range(0..=25);
                password =password.add(RAND_CHAR_SCOPE[index]);
            }  else {
                let index = rng.gen_range(0..=25);
                password =password.add(RAND_CHAR_SCOPE[index].to_uppercase().as_str());
            }
        };
        return password;
    }

    // gnerate 16~20 lenght password, contains number and a~z, A~Z, and special char such as +/-_^&* etc
    fn high_pass_gen(self) -> String {
        let mut rng = rand::thread_rng();
        let pass_length = rng.gen_range(16..=20);
        let  mut order;

        let mut password = String::new();
        loop {
            if password.len()>=pass_length {
                break;
            }
            order = rng.gen_range(0..=3);
            if order == 0{
                let index = rng.gen_range(0..=9);
                password =password.add(RAND_INT_SCOPE[index]);
            }else if order==1 {
                let index = rng.gen_range(0..=25);
                password =password.add(RAND_CHAR_SCOPE[index]);
            }else if order==2 {
                let index = rng.gen_range(0..=25);
                password =password.add(RAND_CHAR_SCOPE[index].to_uppercase().as_str());
            }else {
                let index = rng.gen_range(0..=22);
                password =password.add(RAND_SPECIAL_SIGN[index]);
            }
        };
        return password;
    }

}